#include "xlsx_export.hpp"
#include "utils/path_utils.hpp"
#include <xlsxwriter.h>
#include <filesystem>
#include <numeric>
#include <fmt/format.h>

#include "app/app_base.hpp"

namespace fs = std::filesystem;

namespace Export
{
    std::string ExportToXls(const std::string& date_start, const std::string& date_end, const StatisticsResult& r,
        double base_time)
    {
        fs::path base = GetDesktopPath();
        base /= fmt::format("DiaryApp_Export_{}.xlsx", time(nullptr));

        std::string path = absolute(base).string();

        lxw_workbook* workbook = workbook_new(absolute(base).string().c_str());

        lxw_worksheet* worksheet = workbook_add_worksheet(workbook, (date_start + "至" + date_end).c_str());

        // some format
        const auto bold_black = workbook_add_format(workbook);
        format_set_bold(bold_black);
        format_set_font_color(bold_black, LXW_COLOR_BLACK);

        const auto bold_red = workbook_add_format(workbook);
        format_set_bold(bold_red);
        format_set_font_color(bold_red, LXW_COLOR_RED);

        const auto bold_green = workbook_add_format(workbook);
        format_set_bold(bold_green);
        format_set_font_color(bold_green, LXW_COLOR_GREEN);

        const auto merge_format_l1 = workbook_add_format(workbook);
        format_set_align(merge_format_l1, LXW_ALIGN_CENTER);
        format_set_align(merge_format_l1, LXW_ALIGN_VERTICAL_CENTER);
        format_set_bold(merge_format_l1);
        format_set_bg_color(merge_format_l1, LXW_COLOR_ORANGE);
        format_set_border(merge_format_l1, LXW_BORDER_THIN);

        const auto merge_format_l2 = workbook_add_format(workbook);
        format_set_align(merge_format_l2, LXW_ALIGN_CENTER);
        format_set_align(merge_format_l2, LXW_ALIGN_VERTICAL_CENTER);
        format_set_bold(merge_format_l2);
        format_set_bg_color(merge_format_l2, LXW_COLOR_LIME);
        format_set_border(merge_format_l2, LXW_BORDER_THIN);

        worksheet_merge_range(worksheet, 0, 0, 0, 5, "", nullptr);

        // 概要信息
        if (base_time == 0.0) // 没有指定基准时间
        {
            char t1[] = "总工时：";
            lxw_rich_string_tuple f1{ nullptr, t1 };

            char t2[16]{};
            fmt::format_to(t2, "{:.2f}", r.total_time);
            lxw_rich_string_tuple f2{ bold_black, t2 };

            char t3[] = " 小时（100.00% 投入）";
            lxw_rich_string_tuple f3{ nullptr, t3 };

            lxw_rich_string_tuple* fs[] = { &f1, &f2, &f3, nullptr };
            worksheet_write_rich_string(worksheet, CELL("A1"), fs, nullptr);
        }
        else
        {
            char t1[] = "总工时：";
            lxw_rich_string_tuple f1{ nullptr, t1 };

            char t2[16]{};
            fmt::format_to(t2, "{:.2f}", r.total_time);
            lxw_rich_string_tuple f2{ bold_black, t2 };
            if (r.total_time > base_time) // 加班
                f2.format = bold_green;
            else if (r.total_time < base_time)
                f2.format = bold_red;

            char t3[] = " 小时（";
            lxw_rich_string_tuple f3{ nullptr, t3 };

            char t31[32]{};
            fmt::format_to(t31, "{:.4f}%", r.total_time / base_time * 100.0);
            lxw_rich_string_tuple f31{ bold_black, t31 };
            if (r.total_time > base_time) // 加班
                f31.format = bold_green;
            else if (r.total_time < base_time)
                f31.format = bold_red;

            char t32[] = " 投入)，基准工时：";
            lxw_rich_string_tuple f32{ nullptr, t32 };

            char t4[16];
            fmt::format_to(t4, "{:.2f}", base_time);
            lxw_rich_string_tuple f4{ bold_black, t4 };

            char t5[] = " 小时。";
            lxw_rich_string_tuple f5{ nullptr, t5 };

            lxw_rich_string_tuple* fs[] = { &f1, &f2, &f3, &f31, &f32, &f4, &f5, nullptr };
            worksheet_write_rich_string(worksheet, CELL("A1"), fs, nullptr);
        }

        lxw_row_t current_write_row = 2;
        lxw_row_t level_1_begin_row = current_write_row;
        lxw_row_t level_2_begin_row = current_write_row;

        double const total_time = base_time == 0.0 ? r.total_time : base_time;

        // 工作详情
        for (auto const& x : r.tags)
        {
            if (x.sub_tags.empty())
            {
                // 只有一层标签，直接写第三列
                auto items = App->Sql()->GetItemsByTagAndDate(date_start, date_end, x.tag_id, 0);
                if (!items.empty())
                {
                    for (auto& y : items)
                    {
                        worksheet_write_string(worksheet, current_write_row, 2, y.create_date.c_str(), nullptr);
                        worksheet_write_string(worksheet, current_write_row, 3, y.comment.c_str(), nullptr);
                        std::string text = fmt::format("{:.2f}小时（{:.4f}天）", y.hour, y.hour / 8.0);
                        worksheet_write_string(worksheet, current_write_row, 4, text.c_str(), nullptr);
                        text = fmt::format("{:.4f}%", y.hour / total_time * 100.0);
                        worksheet_write_string(worksheet, current_write_row, 5, text.c_str(), nullptr);
                        ++current_write_row;
                    }

                    // 合并第一第二列
                    worksheet_merge_range(worksheet, level_2_begin_row, 0, current_write_row - 1, 1, x.tag_name.c_str(), merge_format_l1);

                    // 更新范围
                    level_1_begin_row = level_2_begin_row = current_write_row;
                }
            }
            else
            {
                for (auto const& y : x.sub_tags)
                {
                    // 有二级标签，写第3列后合并第2列
                    auto items = App->Sql()->GetItemsByTagAndDate(date_start, date_end, x.tag_id, y.tag_id);
                    if (!items.empty())
                    {
                        for (auto& z : items)
                        {
                            worksheet_write_string(worksheet, current_write_row, 2, z.create_date.c_str(), nullptr);
                            worksheet_write_string(worksheet, current_write_row, 3, z.comment.c_str(), nullptr);
                            std::string text = fmt::format("{:.2f}小时（{:.4f}天）", z.hour, z.hour / 8.0);
                            worksheet_write_string(worksheet, current_write_row, 4, text.c_str(), nullptr);
                            text = fmt::format("{:.4f}%", z.hour / total_time * 100.0);
                            worksheet_write_string(worksheet, current_write_row, 5, text.c_str(), nullptr);
                            ++current_write_row;
                        }

                        // 合并第一第二列
                        if (current_write_row - level_2_begin_row > 1)
                            worksheet_merge_range(worksheet, level_2_begin_row, 1, current_write_row - 1, 1, y.tag_name.c_str(), merge_format_l2);
                        else
                            worksheet_write_string(worksheet, level_2_begin_row, 1, y.tag_name.c_str(), merge_format_l2);

                        // 更新范围
                        level_2_begin_row = current_write_row;
                    }
                }

                // 合并第1列
                if (current_write_row - level_1_begin_row > 1)
                    worksheet_merge_range(worksheet, level_1_begin_row, 0, current_write_row - 1, 0, x.tag_name.c_str(), merge_format_l1);
                else
                    worksheet_write_string(worksheet, level_1_begin_row, 0, x.tag_name.c_str(), merge_format_l1);

                // 更新起始位置
                level_1_begin_row = current_write_row;
            }
        }

        if (workbook_close(workbook) == LXW_NO_ERROR)
            return path;
        return {};
    }
}
